<template>
  <div ref="mapContainer" class="map-container"></div>
</template>

<script setup>
import { nextTick, onMounted, ref, defineExpose } from 'vue';
import 'maplibre-gl/dist/maplibre-gl.css';
import maplibregl from 'maplibre-gl';
import styleData from './custom-style.json';
import {MaplibreTerradrawControl} from '@watergis/maplibre-gl-terradraw'  //0.5 版本适用、测量后自定义显示适用
import '@watergis/maplibre-gl-terradraw/dist/maplibre-gl-terradraw.css'
import { ElMessage, ElMessageBox } from 'element-plus'
import { distance, area, centroid } from '@turf/turf';

import { getCurrentInstance } from 'vue';
import { fa } from 'element-plus/es/locales.mjs';
const { appContext } = getCurrentInstance();
const emitter = appContext.config.globalProperties.$emitter;

const props = defineProps({
  // 地图中心点坐标
  center: {
    type: Array,
    default: [102.74, 25.11]
  },
  // 初始 地图缩放级别
  zoom: {
    type: Number,
    default: 17
  }
})

const mapContainer = ref(null); //地图div
const map = ref(null) //地图实体
const popup = ref(null) //弹窗
const drawInstance = ref(null) // 绘画插件
const isCount = ref(false) //是否计算
onMounted(() => {
  if (mapContainer.value) {
    map.value = new maplibregl.Map({
      container: mapContainer.value, // 容器的ID
      // style: 'https://pm.resource.jcsmartcity.cn/test/test.json', // 样式URL
      style: styleData, //底图瓦片
      center: props.center, // 地图中心点坐标
      zoom: props.zoom, // 地图缩放级别
      maxZoom: 18, // 设置最大缩放层级为 18
      attributionControl: false, // 隐藏版权信息
      // 请确保添加你的 Mapbox 访问令牌
      // accessToken: '你的Mapbox访问令牌',
    });

    // 全屏按钮 控件
    map.value.addControl(new maplibregl.FullscreenControl(), 'bottom-right')

    // 地理定位控件
    map.value.addControl(new maplibregl.GeolocateControl({
        positionOptions: {
            enableHighAccuracy: true
        },
        trackUserLocation: true
    }), 'bottom-right');

    // 包含缩放按钮和指南针 控件
    map.value.addControl(new maplibregl.NavigationControl(), 'bottom-right');

    // 水印 控件
    // map.value.addControl(new maplibregl.LogoControl({compact: false}), 'bottom-right');

    // 控件显示地图上的距离与地面上相应距离的比值 控件
    // 当设置 unit: 'imperial' 时，比例尺将使用英制单位进行显示
    map.value.addControl(new maplibregl.ScaleControl({
        maxWidth: 80,
        unit: 'imperial'
    }), 'bottom-left');

    // 显示地形 控件
    // map.value.addControl(new maplibregl.TerrainControl({
    //     source: "terrain"
    // }), 'bottom-right');

    // 监听地图点击事件
    map.value.on('click', (e) => {
      clickMap(e)
    });

    // 监听地图缩放事件
    map.value.on('zoom', (e) => {
      changeMpaZoom(e)
    });

    // 使用插件 @watergis/maplibre-gl-terradraw
    // 在地图上绘制各种形式的几何图形，如点、线或多边形
    // https://terradraw.water-gis.com/ 绘画工具官网
    // https://watergis.github.io/maplibre-gl-terradraw/classes/MaplibreTerradrawControl.MaplibreTerradrawControl.html api
    const drawControl = new MaplibreTerradrawControl({
      // render 切换工具展开、 point 点、 linestring 线、 polygon 面、 rectangle 矩形、 circle 圆形、 freehand 跟随鼠标画多边形、angled-rectangle 倾斜矩形、 sensor 雷达梯形、 sector 扇形、 select 选择、 delete-selection 删除选择图形、 delete 删除全部图形
      modes: ['render','point','linestring','polygon','rectangle','circle','freehand','angled-rectangle','sensor','sector','select','delete-selection','delete'],
      open: false, //设置为false以允许收缩
    });
    // top-right top-left bottom-right bottom-left
    map.value.addControl(drawControl);
    
    // 监听画图事件
    drawInstance.value = drawControl.getTerraDrawInstance();
    console.log('控件实体', drawInstance.value);
    
    if (drawInstance.value) {
      // 变化
      drawInstance.value.on('change', (id) => {
        console.log('图形变化', id)
      });
      // 撤销选定
      drawInstance.value.on('deselect', (id) => {
        console.log('撤销图形选定', id)
      });
      // 完成
      drawInstance.value.on('finish', (id) => {
        console.log('图形绘画完成', id)
        const snapshot = drawInstance.value.getSnapshot();
				// const feature = snapshot?.find((f) => f.id === id && f.geometry.type === 'Polygon'); //这个控制了多边形
        const feature = snapshot?.find((f) => f.id === id);

        // 如果是划线，并且需要测算距离
        if(feature.properties.mode === 'linestring' && isCount.value){
          const geojsonSource = map.value.getStyle().sources['measureLine-source']
          if (geojsonSource) {
            const geojsonSource = map.value.getStyle().sources['measureLine-source'];
            if (geojsonSource) {
              const coordinates = feature.geometry.coordinates;

              // Calculate distance for each segment of LineString feature
              for (let i = 0; i < coordinates.length - 1; i++) {
                const start = coordinates[i];
                const end = coordinates[i + 1];
                const result = distance(start, end, { units: 'kilometers' });

                const segment = JSON.parse(JSON.stringify(feature));
                segment.id = `${segment.id}-${i}`;
                segment.geometry.coordinates = [start, end];
                segment.properties = {
                  ...segment.properties,
                  originalId: feature.id,
                  distance: result.toFixed(2),
                  unit: 'km'
                };

                if (typeof geojsonSource.data !== 'string' && geojsonSource.data.type === 'FeatureCollection') {
                  geojsonSource.data.features.push(segment);
                }
              }

              // Update GeoJSON source with new data
              map.value.getSource('measureLine-source').setData(geojsonSource.data);
              map.value.moveLayer('layer-measureLine-json');
            }
          }
        }


        // 绘画多边形---显示面积
        if(feature.properties.mode === 'polygon' && isCount.value){
          const geojsonSource = map.value.getStyle().sources['measurePolygone-source']
          if (geojsonSource) {
            const geojsonSource = map.value.getStyle().sources['measurePolygone-source'];
            if (geojsonSource) {
              const result = area(feature.geometry);
              const point = JSON.parse(JSON.stringify(feature));
              point.id = point.id + "-area-label";
              point.geometry = centroid(feature.geometry).geometry;
              point.properties.originalId = feature.id;
    
              // convert unit to ha or km2 if value is larger
              let outputArea = result;
              let outputUnit = 'm2'
              if (result > 10000) {
                outputArea = result / 10000
                outputUnit = 'ha'
              } else if (result > 1000) {
                outputArea = result / 1000
                outputUnit = 'km2'
              }
    
              point.properties.area = outputArea.toFixed(2);
              point.properties.unit = outputUnit;
    
              if (
                typeof geojsonSource.data !== 'string' &&
                geojsonSource.data.type === 'FeatureCollection'
              ) {
                geojsonSource.data.features.push(point);
              }

              // Update GeoJSON source with new data
              map.value.getSource('measurePolygone-source').setData(geojsonSource.data);
              map.value.moveLayer('layer-measurePolygone-json');
            }
          }
        }
        
        changePainting(feature) //绘画完成事件
        // drawControl.deactivate() //停用Terra绘制以停止绘制,这个api可以停用，但是会清空绘画  激活：drawControl.activate()
        drawInstance.value.setMode('render') //停止继续绘画功能，改变控件状态
      });
      // 准备
      drawInstance.value.on('ready', (id) => {
        console.log('准备绘制图形', id)
      });
      // 选择
      drawInstance.value.on('select', (id) => {
        console.log('选择图形', id)
      });
    }

    // 模式变化 应该只会监听 启用、停用
    drawControl.on('mode-changed', (e) => {
      console.log('模式变化', e)
    });
    // 删除 控件删除特性时发出的事件
    drawControl.on('feature-deleted', (e) => {
      console.log('删除图形', e)

      // 划线--测量距离显示的数字，需要删除
      const geojsonSourceLine = map.value.getStyle().sources['measureLine-source']
      if (geojsonSourceLine) {
        // get IDs in current TerraDraw snapshot
        const snapshot = drawInstance.value.getSnapshot();
        const features = snapshot?.filter(
          (feature) => feature.properties.mode === 'linestring'
        );
        const ids = features.map((f) => f.id);
        if (
          typeof geojsonSourceLine.data !== 'string' &&
          geojsonSourceLine.data.type === 'FeatureCollection'
        ) {

          // Delete label features if originalId does not exist anymore.
          geojsonSourceLine.data.features = geojsonSourceLine.data.features.filter((f) =>
            ids.includes(f.properties?.originalId)
          );
        }
        map.value.getSource('measureLine-source').setData(geojsonSourceLine.data);
        map.value.moveLayer('layer-measureLine-json');
      }


      // 画面--计算面积显示的数字，需要删除
      const geojsonSourcePolygon = map.value.getStyle().sources['measurePolygone-source']
      if (geojsonSourcePolygon) {
        // get IDs in current TerraDraw snapshot
        const snapshot = drawInstance.value.getSnapshot();
        const features = snapshot?.filter((feature) => feature.geometry.type === 'Polygon');
        const ids = features.map((f) => f.id);
        if (
          typeof geojsonSourcePolygon.data !== 'string' &&
          geojsonSourcePolygon.data.type === 'FeatureCollection'
        ) {
          // Delete label features if originalId does not exist anymore.
          geojsonSourcePolygon.data.features = geojsonSourcePolygon.data.features.filter((f) =>
            ids.includes(f.properties?.originalId)
          );
        }
        map.value.getSource('measurePolygone-source').setData(geojsonSourcePolygon.data);
        map.value.moveLayer('layer-measurePolygone-json');
      }

      // 开启  删除后好像被禁止了不能继续绘画，直接setMode会报错，开启后setMode就不报错了
      drawControl.activate()
    });


    // 兄弟组件 监听事件
    // 切换隐藏显示图层
    emitter.on('changeMapLevel', (data) => {
      toggMiningArealeLayer(data);
    })

    // 切换飞行
    emitter.on('changeMapFlyTo', (data) => {
      mapFlyTo(data);
    })

    // 改变 绘画工具 状态
    emitter.on('changePaintingTools', (data) => {
      drawInstance.value.setMode(data.mode)
      if(data.count){  // 只有 measure 需要计算距离、面积，其他不计算
        isCount.value = true
      }else{
        isCount.value = false
      }
    })

  }
});

// 加载矿区图层
nextTick(() => {
  map.value.on('load', () => {
    // 源
    map.value.addSource('miningArea-source', {
      type: 'vector',
      url: "http://39.129.95.76:50300/polygons"
    });

    // 添加填充图层-面
    map.value.addLayer({
      id: 'miningArea-layer-fill',
      type: 'fill',
      source: 'miningArea-source',
      "source-layer": "polygons", // 根据实际的 source-layer id名称替换
      "minzoom": 5,
      layout: { visibility: 'visible' }, //none 默认隐藏   visible 默认显示
      paint: {
        'fill-color': '#ff0000', // 设置填充颜色
        'fill-opacity': 0.5, // 设置填充透明度
        "fill-outline-color": "rgba(0, 0, 0, 1)"
      }
    });

    // 添加文字
    map.value.addLayer({
      id: 'miningArea-layer-symbol',
      type: 'symbol',
      source: 'miningArea-source',
      "source-layer": "polygons", // 根据实际的 source-layer id名称替换
      "minzoom": 10,
      layout: {
        'text-field': "{name}", // 从属性中获取显示的文本
        'text-variable-anchor': ['left', 'right', 'top', 'bottom'],
        'text-radial-offset': 0.5, // 文本偏移
        'text-justify': 'center',
        'text-size': 14, // 文本大小
        'text-transform': 'uppercase', // 文本大写
        visibility: 'visible'
      },
      paint: {
        'text-color': '#ffffff', // 文本颜色
        'text-halo-color': '#000000', // 文本光晕颜色
        'text-halo-width': 1 // 文本光晕宽度
      }
    });


    // 给添加的实体，增加鼠标样式
    // 填充层的
    map.value.on('mouseenter', 'miningArea-layer-fill', (e) => {
      // 改变鼠标样式为pointer
      map.value.getCanvas().style.cursor = 'pointer';
    });
    map.value.on('mouseleave', 'miningArea-layer-symbol', (e) => {
      // 还原鼠标样式
      map.value.getCanvas().style.cursor = '';
    });

    // 文字的
    map.value.on('mouseenter', 'miningArea-layer-symbol', (e) => {
      // 改变鼠标样式为pointer
      map.value.getCanvas().style.cursor = 'pointer';
    });
    map.value.on('mouseleave', 'miningArea-layer-fill', (e) => {
      // 还原鼠标样式
      map.value.getCanvas().style.cursor = '';
    });


    // 为线距离面积标签添加GeoJSON源
    const source = {
			type: 'geojson',
			data: { type: 'FeatureCollection', features: [] }
		};
    map.value.addSource('measureLine-source', source);

    // 添加GeoJSON图层以显示 距离 标签
    const layerLine = {
			id: 'layer-measureLine-json',
			type: 'symbol',
			source: 'measureLine-source',
			filter: ['match', ['geometry-type'], ['LineString'], true, false],
			layout: {
				'text-field': ['concat', ['to-string', ['get', 'distance']], ' ', ['get', 'unit']],
				'symbol-placement': 'line',
				'text-font': ['Open Sans Semibold'],
				'text-size': 12,
				'text-overlap': 'always',
			},
			paint: {
				'text-halo-color': '#ffffff',
				'text-halo-width': 1,
				'text-color': '#ff0000'
			}
		};
    map.value.addLayer(layerLine);



    // 为线距离面积标签添加GeoJSON源
    map.value.addSource('measurePolygone-source', source);
    // 添加GeoJSON图层以显示 面积 标签
    const layerPolygon = {
			id: 'layer-measurePolygone-json',
			type: 'symbol',
			source: 'measurePolygone-source',
			filter: ['match', ['geometry-type'], ['Point'], true, false],
			layout: {
				'text-field': ['concat', ['to-string', ['get', 'area']], ' ', ['get', 'unit']],
				'symbol-placement': 'point',
				'text-font': ['Open Sans Semibold'],
				'text-size': 12,
				'text-overlap': 'always'
			},
			paint: {
				'text-halo-color': '#ffffff',
				'text-halo-width': 1,
				'text-color': '#ff0000'
			}
		};
    map.value.addLayer(layerPolygon);

  });
})


// 切换图层可见性
// layerArr 图层id数组
function toggMiningArealeLayer(layerArr) {
  // console.log('切换矿区图层隐藏显示', layerArr);
  const mapAllLayers = map.value.style._order  //地图所有图层
  const mapBaseMap = ['gaodeImage-tiles', 'gaodeImageAnnotation-tiles', 'gaodeElectron-tiles']  //地图底图图层
  // 如果切换图层，包含 地图底图，逻辑里可以隐藏地图，反之不能隐藏底图
  const isContained = layerArr.every(item => mapBaseMap.includes(item)); //需要切换的图层是否包含底图
  let changeMapLayers = [] //即将切换的所有图层 layerArr需要显示隐藏的图层，其他的全部隐藏
  if(isContained){ 
    changeMapLayers = mapAllLayers
  }else{
    changeMapLayers = mapAllLayers.filter(item => !mapBaseMap.includes(item))
  }
  for (let item of changeMapLayers) {
    if(layerArr.includes(item)){  //切换显示图层
      const layerId = item
      // 检查图层是否存在，并切换其可见性
      if (map.value.getLayer(layerId)) {
        const currentVisibility = map.value.getLayoutProperty(layerId, 'visibility');
        // 如果切换当前底图，不隐藏，不然页面空白了
        map.value.setLayoutProperty(layerId, 'visibility', isContained?'visible':currentVisibility === 'visible' ? 'none' : 'visible');
      } else {
        console.warn(`图层 ${layerId} 不存在。`);
      }
    }else{ //隐藏其他图层
      const layerId = item
      // 检查图层是否存在，并切换其可见性
      if (map.value.getLayer(layerId)) {
        const currentVisibility = map.value.getLayoutProperty(layerId, 'visibility');
        map.value.setLayoutProperty(layerId, 'visibility', currentVisibility === 'visible' ? 'none' : 'none');
      } else {
        console.warn(`图层 ${layerId} 不存在。`);
      }
    }
  }
  

  // 关闭弹窗
  if(popup.value){
    popup.value.remove(); 
  }
}


// 地图点击事件
function clickMap(e) {
  console.log('点击地图', e);
  
  const features = map.value.queryRenderedFeatures(e.point, {
      layers: ['miningArea-layer-fill', 'miningArea-layer-symbol'] // 替换为你的图层ID
  });

  if (features.length > 0) {
    // 点击矿区
    if(features[0].layer.id == 'miningArea-layer-fill' || features[0].layer.id == 'miningArea-layer-symbol'){
      const feature = features[0]; // 获取第一个特征（可能需要根据实际情况选择）
      console.log('实体-打印特征以查看其属性', feature); // 打印特征以查看其属性

      // 确保弹窗显示在正确的位置
      // const coordinates = feature.geometry.coordinates[0][0];
      // while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
      //     coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
      // }

      popup.value = new maplibregl.Popup({
            closeButton: false, // 不显示关闭按钮
            anchor: 'left', // 设置锚点为顶部

            // 这里因为引入了 css，所以不要了
            // offset: [136, -1166], // 根据需要调整偏移量，这里的-30像素是示例值，您可能需要根据实际情况调整
            className: 'custom-popup'
        })
        // .setLngLat(coordinates)
        .setLngLat(e.lngLat)
        .setHTML(`
          <div class="popup-content">
            <h3>${feature.properties.name}</h3>
            <p>证书编号： ${feature.properties.certificate_number?feature.properties.certificate_number:''}</p>
            <p>区划： ${feature.properties.district?feature.properties.district:''}</p>
            <p>开发时间： ${feature.properties.fill_time?feature.properties.fill_time:''}</p>
            <p>批准机关： ${feature.properties.issue_authority?feature.properties.issue_authority:''}</p>
            <p>批准时间： ${feature.properties.issue_time?feature.properties.issue_time:''}</p>
            <p>位置： ${feature.properties.location?feature.properties.location:''}</p>
            <p>采矿所有者： ${feature.properties.mining_owner?feature.properties.mining_owner:''}</p>
            <p>所有者组织代码： ${feature.properties.org_code?feature.properties.org_code:''}</p>
            <p>所有者地址： ${feature.properties.owner_address?feature.properties.owner_address:''}</p>
            <p>许可证编号： ${feature.properties.permit_number?feature.properties.permit_number:''}</p>
            <p>公开时间： ${feature.properties.public_time?feature.properties.public_time:''}</p>
            <p>区域面积： ${feature.properties.survey_area?feature.properties.survey_area:''}</p>
            <p>调查单位地址： ${feature.properties.survey_unit_address?feature.properties.survey_unit_address:''}</p>
            <p>有效起始时间： ${feature.properties.valid_start_time?feature.properties.valid_start_time:''}</p>
            <p>有效结束时间： ${feature.properties.valid_end_time?feature.properties.valid_end_time:''}</p>

            <button id="popupButton">点击我</button>
          </div>
        `)
        .addTo(map.value);
      
      // 获取按钮元素并添加点击事件监听器
      const button = popup.value.getElement().querySelector('#popupButton');
      button.addEventListener('click', () => {
        // 在这里处理按钮点击事件
        console.log('Button clicked!');
        // 可以在这里关闭弹窗
        popup.value.remove(); // 关闭弹窗
      });

      // 这里不会直接更改颜色，但你可以根据特征属性来设置数据驱动的样式
      // 或者使用 setFeatureState 和 state 驱动的样式

    }else{

    }
      
  }else{
    // 没有点击实体
    // ElMessage({
    //   message: e.lngLat.lat + '，' + e.lngLat.lng,
    //   type: 'success',
    // })
  }
}


// 监听地图缩放事件
function changeMpaZoom(e){
  const zoomLevel = map.value.getZoom();
  console.log('当前缩放层级：', zoomLevel);
  // 在这里根据缩放层级执行相应的操作


  // 关闭弹窗
  if(popup.value){
    popup.value.remove(); 
  }
}


// 飞到指定位置
function mapFlyTo(data){
  map.value.flyTo({
    center: data.center?data.center:[116.14226818084717, 39.94195584345027], // 目标位置的经纬度坐标
    zoom: data.zoom?data.zoom:14, // 目标缩放级别
    // curve 参数
    // 1.4：这是用户研究中选择的平均值，提供了一个平衡的动画效果
    // Math.pow(6, 0.25)：这个值相当于均方根平均速度，提供了一个特定的动画节奏
    // 1：这个值会产生一个圆形运动，即没有缩放的动画效果
    curve: data.curve?data.curve:1.4, // 飞行动画的曲线程度（1 表示直线飞行， 1.4 贝塞尔曲线参数，控制飞行路径的平滑度）
    duration: data.duration?data.duration:4000, // 飞行动画的持续时间（毫秒），如果设置了此选项，则 speed 和 curve 将被忽略
    maxDuration: data.maxDuration?data.maxDuration:5000, // 最大动画持续时间，5000毫秒或5秒
    minZoom: data.minZoom?data.minZoom:10, // 飞行过程中的最小缩放级别
    // padding参数的作用是确保在执行动画或转换视图时，目标地点或特征在地图视图中完全可见
    padding: data.padding?data.padding:{ top: 10, bottom: 50, left: 10, right: 50 }, // 视图填充
    // screenSpeed参数控制的是地图在屏幕上移动的速度，单位是像素/秒。这个参数影响的是地图上内容移动的快慢，与实际地理距离无关
    screenSpeed: data.screenSpeed?data.screenSpeed:2, // 屏幕速度，像素/秒
    // speed参数控制的是飞行动画的速率，单位是屏幕像素/秒。这个参数影响的是整个飞行动画的快慢，包括缩放和平移
    speed: data.speed?data.speed:0.2, // 飞行动画的速度（每秒移动的像素数）
  })
}


// 监听 绘画完成事件
function changePainting(feature){
  // console.log('绘画的实体:', feature);
  emitter.emit('paintingCompleted', feature);
}

</script>
<!-- 参考 -->
<!-- https://maplibre.org/maplibre-gl-js/docs/examples/set-popup/ -->
<!-- https://zmx2321.github.io/blog/pages/accumulation/front/vue-note-5.html#_3-%E5%B0%81%E8%A3%85%E5%88%9D%E5%A7%8B%E5%8C%96%E5%9C%B0%E5%9B%BE%E6%96%B9%E6%B3%95 -->

<style scoped>
.map-container {
  width: 100%;
  height: 100%;
  overflow: hidden;
  /* position: absolute;
  left: 0;
  top: 0;
  z-index: -1; */
}
</style>

<style>
.custom-popup .maplibregl-popup-content {
    background-color: #fff;
    color: #000;
    font-size: 14px;
}
.custom-popup .maplibregl-popup-content .popup-content{
  width: 320px;
}
.custom-popup .maplibregl-popup-content .popup-content h3{
  margin-bottom: 10px;
}
.custom-popup .maplibregl-popup-content .popup-content p{
  padding: 4px 0;
  border-bottom: 1px solid #EBEDF0;
}
.custom-popup .maplibregl-popup-content .popup-content button{
  margin-top: 20px;
}
.custom-popup .maplibregl-popup-tip {
  /* border-right-color: #f54647 !important; 设置弹窗箭头的颜色 */
}


/* 隐藏绘画工具 */
.maplibregl-terradraw-render-button {
  display: none !important;
}
</style>
